import { isFinite, has } from "lodash";
import React, { useState, useEffect, useRef } from "react";
import ReactDOM from 'react-dom';
import resizeObserver from "@/services/resizeObserver";
import { RendererPropTypes } from "@/visualizations/prop-types";
// import mdc from "markdown-core/src/index-node";
import Chart from 'chart.js';
import { axios } from "@/services/axios";
import { getCounterData } from "@/lib/functions";
import { getUrlParameterValue, getUrlParameters } from "@/lib/DateRangeParameter";
import { currentUser } from "@/../../../../client/app/services/auth";

export default function Renderer({ data, options, queryId, refreshStartedAt, scale, scaleX }) {
  const [markdownText, setMarkdownText] = useState(options.markdown);
  const [refreshAt, setRefreshAt] = useState(refreshStartedAt);
  const [isRefresh, setIsRefresh] = useState(false);
  const markdownRef = useRef(null);
  const showPortal = window.location.search.includes("show_portal") && localStorage.getItem('colorstyle_color');

  const functionInstantGet = (query, storageName, markdownText, oldstr, functions) => {
    axios.get(`api/queries/${query}/results.json`).then(response => {
      let rows1 = response.query_result.data.rows;
      let result = getCounterData(rows1, functions);
      let mdtext = markdownText;
      if (!!functions.numberArray) {
        mdtext = mdtext.replace('"' + oldstr +'"', result);
      }
      mdtext = mdtext.replace(oldstr, result);
      setMarkdownText(mdtext);

      try {
        sessionStorage.setItem(storageName, JSON.stringify(rows1));
      } catch(e) {
      } finally {
        return;
      } 
    }).catch(error => {
      let mdtext = markdownText.replace(oldstr, error);
      setMarkdownText(mdtext);
    })
  };

  const functionInstant = (query, parameters, storageName, markdownText, oldstr, functions) => {
    const max_age = 0;
    axios.post(`api/queries/${query}/results`, { query, parameters, max_age }).then(response => {
      if ("job" in response) {
        const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
        let loop_times = 0;   
        function loop() {
          axios.get(`api/jobs/${response.job.id}`).then(response => {
            if (!!response.job.query_result_id) {
              axios.get(`api/query_results/${response.job.query_result_id}`).then(response => {
                let rows1 = response.query_result.data.rows;
                let result = getCounterData(rows1, functions);
                let mdtext = markdownText;
                if (!!functions.numberArray) {
                  mdtext = mdtext.replace('"' + oldstr +'"', result);
                }
                mdtext = mdtext.replace(oldstr, result);
                setMarkdownText(mdtext);

                try {
                  sessionStorage.setItem(storageName, JSON.stringify(rows1));
                } catch(e) {
                } finally {
                  return;
                } 
              });
            } else if (response.job.status === 1 || response.job.status === 2) {
              loop_times = loop_times + 1;
              if (loop_times <= 10) {
                sleep(loop_times * 500).then(()=>{loop();});
              }
            }
          });
        }
        
        if (loop_times < 1) {
          loop_times = loop_times + 1;
          sleep(loop_times * 500).then(()=>{loop();});
        }
      } else {
        let rows2 = response.query_result.data.rows;
        let result = getCounterData(rows2, functions);
        let mdtext = markdownText;
        if (!!functions.numberArray) {
          mdtext = mdtext.replace('"' + oldstr +'"', result);
        }
        mdtext = mdtext.replace(oldstr, result);
        setMarkdownText(mdtext);
  
        try {
          sessionStorage.setItem(storageName, JSON.stringify(rows2));
        } catch(e) {}
      }
    }).catch(error => {
      let mdtext = markdownText.replace(oldstr, error);
      setMarkdownText(mdtext);
    })
  };

  const functionLazyGet = (query, storageName, elementName, currentRef, functions) => {
    let dom = ReactDOM.findDOMNode(currentRef);
    axios.get(`api/queries/${query}/results.json`).then(response => {
      let rows1 = response.query_result.data.rows;
      let result = getCounterData(rows1, functions);
      let element = dom.querySelector(elementName);
      if (element) {
        element.outerHTML = result;
      } else {
        sessionStorage.setItem(elementName, result.toString());
      }

      try {
        sessionStorage.setItem(storageName, JSON.stringify(rows1));
      } catch(e) {
      } finally {
        return;
      } 
    }).catch(error => {
      let element = dom.querySelector(elementName);
      if (element) element.outerHTML = error;
    })
  }

  const functionLazy = (query, parameters, storageName, elementName, currentRef, functions) => {
    let dom = ReactDOM.findDOMNode(currentRef);
    const max_age = 0;
    axios.post(`api/queries/${query}/results`, { query, parameters, max_age }).then(response => {
      if ("job" in response) {
        const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
        let loop_times = 0;   
        function loop() {
          axios.get(`api/jobs/${response.job.id}`).then(response => {
            if (!!response.job.query_result_id) {
              axios.get(`api/query_results/${response.job.query_result_id}`).then(response => {
                let rows1 = response.query_result.data.rows;
                let result = getCounterData(rows1, functions);
                let element = dom.querySelector(elementName);
                if (element) {
                  element.outerHTML = result;
                } else {
                  sessionStorage.setItem(elementName, result.toString());
                }

                try {
                  sessionStorage.setItem(storageName, JSON.stringify(rows1));
                } catch(e) {
                } finally {
                  return;
                } 
              });
            } else if (response.job.status === 1 || response.job.status === 2) {
              loop_times = loop_times + 1;
              if (loop_times <= 10) {
                sleep(loop_times * 500).then(()=>{loop();});
              }
            }
          });
        }
        
        if (loop_times < 1) {
          loop_times = loop_times + 1;
          sleep(loop_times * 500).then(()=>{loop();});
        }
      } else {
        let rows2 = response.query_result.data.rows;  
        let result = getCounterData(rows2, functions);
        let element = dom.querySelector(elementName);
        if (element) {
          element.outerHTML = result;
        } else {
          sessionStorage.setItem(elementName, result.toString());
        }
  
        try {
          sessionStorage.setItem(storageName, JSON.stringify(rows2));
        } catch(e) {} 
      }
    }).catch(error => {
      let element = dom.querySelector(elementName);
      if (element) element.outerHTML = error;
    })
  }

  useEffect(() => {
    setMarkdownText(options.markdown);
    if (!!!refreshAt && !!refreshStartedAt) {
      setRefreshAt(refreshStartedAt);
    } else if (!!refreshAt && !!refreshStartedAt) {
      if (refreshAt.isBefore(refreshStartedAt)) {
        setRefreshAt(refreshStartedAt);
        setIsRefresh(true);
      }
    }
  }, [refreshStartedAt]);
  
  useEffect(() => {
    let dom = ReactDOM.findDOMNode(markdownRef.current);
    let mats = /\{\{(.|\n)*?\}\}/m.exec(markdownText);

    if (!mats) {
      // if (!!markdownText) {
      //   require.ensure([], function(require){
      //     import(/* webpackChunkName:"markdown" */ 'markdown-core/src/index-node').then(({default: mdc}) => {  
      //     dom.innerHTML = mdc.render(markdownText);
      //     mdc.mermaid.init(undefined, dom.querySelectorAll('.mermaid'));
      //     dom.querySelectorAll('.chartjs').forEach(element => {
      //       try {
      //           new Chart(element, JSON.parse(element.textContent));
      //       } catch (e) {
      //         element.outerHTML = `<pre>Chart.js complains: "${e}"</pre>`;
      //       }
      //     });

      //     for(var i=0, len=sessionStorage.length; i<len; i++){
      //       var key = sessionStorage.key(i);
      //       if (key.indexOf("#functions") === 0) {
      //         var result = sessionStorage.getItem(key);    
      //         let element = dom.querySelector(key);
      //         if (element) element.outerHTML = result;
      //       }    
      //     }
      //     });
      //   }, 'markdown');
      // }
      return;
    }

    if (!(mats instanceof Array)) return;

    let oldstr = mats[0].toString();
    let functions;
    try {
      let objstr = oldstr.substring(1, oldstr.length-1)
      functions = JSON.parse(objstr);
    } catch(e) {
      let mdtext = markdownText.replace(oldstr, e);
      setMarkdownText(mdtext);
      return;
    }
    
    if (functions.hasOwnProperty("parameter")) {
      let parameterValue = getUrlParameterValue(functions.parameter)

      let mdtext = markdownText.replace(oldstr, parameterValue);
      setMarkdownText(mdtext);
      return;
    }

    if (functions.hasOwnProperty("cookie")) {
      let cookieStr = "";
      if (!!functions.cookie && showPortal) cookieStr = localStorage.getItem(functions.cookie);
      
      let mdtext = markdownText.replace(oldstr, cookieStr);
      setMarkdownText(mdtext);
      return;
    }

    if (functions.hasOwnProperty("random")) {
      var randomStr = Math.ceil(Math.random()*10000).toString();
      let mdtext = markdownText.replace(oldstr, randomStr);
      setMarkdownText(mdtext);
      return;
    }

    if (functions.hasOwnProperty("session")) {
      let sessionStr = "";
      if (!!functions.session) {
        if (functions.session === "scale" || functions.session === "scaley" || functions.session === "scaleY") sessionStr = scale;
        if (functions.session === "scalex" || functions.session === "scaleX") sessionStr = scaleX;
        if (functions.session === "scalemin" || functions.session === "scaleMin") sessionStr = scale<scaleX ? scale : scaleX;
        if (functions.session === "scalemax" || functions.session === "scaleMax") sessionStr = scale>scaleX ? scale : scaleX;
        if (functions.session.indexOf("currentUser_") === 0) {
          const userProperty = functions.session.substring(12);
          if (currentUser.hasOwnProperty(userProperty)) {
            sessionStr = currentUser[userProperty];        
          }
        }
      }
      
      let mdtext = markdownText.replace(oldstr, sessionStr);
      setMarkdownText(mdtext);
      return;
    }

    let is_querys = functions.hasOwnProperty("querys");
    let query = functions.query || functions.querys;
    if (!!!query || parseInt(query) === 0) query=queryId;
    delete functions.query
    delete functions.querys
    let parameters = functions.parameters;
    delete functions.parameters
  
    let storageName = query;
    if (parameters) {
      parameters = getUrlParameters(parameters);
      storageName = storageName + JSON.stringify(parameters);
    } 
  
    let rows = sessionStorage.getItem(storageName);
    if (rows) {
      let result = getCounterData(JSON.parse(rows), functions);
      let mdtext = markdownText;
      if (!!functions.numberArray) {
        mdtext = mdtext.replace('"' + oldstr +'"', result);
      }
      mdtext = mdtext.replace(oldstr, result);
      setMarkdownText(mdtext);
    } else if (is_querys) {
      if (isRefresh || (parameters && Object.keys(parameters).length !== 0))
        functionInstant(query, parameters, storageName, markdownText, oldstr, functions);
      else
        functionInstantGet(query, storageName, markdownText, oldstr, functions);
    } else {
      let timestamp = "functions" + (new Date()).valueOf() + Math.random().toString().replace('.','');
      let functionName = "<span id='" + timestamp + "'>……</span>";
      let elementName = "#" + timestamp;
      setMarkdownText(markdownText.replace(oldstr, functionName));  

      if (isRefresh || (parameters && Object.keys(parameters).length !== 0))
        functionLazy(query, parameters, storageName, elementName, markdownRef.current, functions);
      else
        functionLazyGet(query, storageName, elementName, markdownRef.current, functions);
    }
  }, [markdownText, showPortal, isRefresh]);

  return (
    <div className="markdown-visualization-content">
      <article className="body-row-auto scrollbox t-body p-10 markdown" ref={markdownRef} 
        style={showPortal ? {color: localStorage.getItem('colorstyle_color')} : null} />
    </div>
  );
}

Renderer.propTypes = RendererPropTypes;
